#include "common.hpp"
#include "server_TCP.hpp"
#include <memory>
#include <iostream>

#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <thread>
#include <mutex>

#include "thread_pool.hpp"




void service(int socket_fd)
{
    char outbuffer[1024];
    while(true)
    {
        int out_count = read(socket_fd, outbuffer, sizeof(outbuffer) - 1);
        if(out_count > 0)
        {
            outbuffer[out_count] = '\0';
            LOG(wzx::log_level::INFO) << "client say:> " << outbuffer;

            std::string echo_str = "<echo>";
            echo_str += outbuffer;
            write(socket_fd, echo_str.c_str(), echo_str.size());
        }
        else if(out_count == 0)//read返回值为0代表对端关闭连接了
        {
            LOG(wzx::log_level::INFO) << "client quit...";
            break;
        }
        else
        {
            LOG(wzx::log_level::FATAL) << "read failed!!!";
            exit(READ_ERR);    
        }
    }
}

void service_once(int socket_fd)
{
    char outbuffer[1024];

    int out_count = read(socket_fd, outbuffer, sizeof(outbuffer) - 1);
    if(out_count > 0)
    {
        outbuffer[out_count] = '\0';
        LOG(wzx::log_level::INFO) << "client say:> " << outbuffer;

        std::string echo_str = "<echo>";
        echo_str += outbuffer;
        write(socket_fd, echo_str.c_str(), echo_str.size());
    }
    else if(out_count == 0)//read返回值为0代表对端关闭连接了
    {
        LOG(wzx::log_level::INFO) << "client quit...";
    }
    else
    {
        LOG(wzx::log_level::FATAL) << "read failed!!!";
        exit(READ_ERR);    
    }
}


//v1: 多进程版本
void process_version(int listen_socket_fd, int socket_fd)
{
    //v1-单进程问题: 进程accept后, 会一直while进行server, 而不能再响应新的accept
        //解决办法: 创建新的进程去进行server(服务员), 而主进程只进行accept(吆喝)
    //新的问题: 父进程会阻塞等待新进程, 而无法并发继续accepte
        //解决办法1: signal(SIGCHLD, SIG_IGN);//忽略信号

    pid_t id = fork();
    if(id < 0)
    {
        LOG(wzx::log_level::FATAL) << "fork failed!!!";
        exit(FORK_ERR);    
    }
    else if(id == 0)//子进程
    {
        close(listen_socket_fd);//隔离父进程的文件, 增强鲁棒性

        //解决办法2: 子进程再创建孙子进程
        pid_t sub_id = fork();
        if(sub_id < 0)
        {
            LOG(wzx::log_level::FATAL) << "fork failed!!!";
            exit(FORK_ERR); 
        }
        else if(sub_id == 0)//孙子进程 -- 孤儿进程: 被一号进程领养
        {
            service(socket_fd);//执行循环IO操作去
            close(socket_fd);
            exit(NORMAL);
        }
        else//子进程
        {
            close(socket_fd);
            exit(NORMAL); //直接退出
        }
    }
    else//父进程
    {
        close(socket_fd);
        waitpid(id, nullptr, 0);//子进程创建完孙子进程就直接退了, 父进程回收后又可以干自己的事情(accept)去了
    }
}



//v2: 多线程版本
void thread_version(int socket_fd)
{
    //让从线程去service, 并且将它分离, 主线程退出thread_version()后接着accept
    std::thread t(service, socket_fd);
    t.detach();
}




void thread_pool_version(int socket_fd)
{
    task_t task = std::bind(service_once, socket_fd);//参数和函数绑在一起, 形成固定的无参调用类型
    thread_pool<task_t>::get_singleton()->task_push(task);
}




int main(int argc, char* argv[])
{
    //./server_UDP [server_port] [server_ip] //不用传ip, 因为INADDR_ANY
    //./server_UDP [server_port]
    if(argc != 2)
    {
        std::cout << "usage: " << argv[0] << " [server_port]" << std::endl;
        exit(USAGE_ERR);
    }

    LOG_SWITCH_CONSOLE;

    uint16_t port = static_cast<uint16_t>(std::stoi(argv[1]));

    //v1
    //std::unique_ptr<server_tcp> st_p = std::make_unique<server_tcp>(port, process_version);

    //v2
    //std::unique_ptr<server_tcp> st_p = std::make_unique<server_tcp>(port, thread_version);

    //v3
    thread_pool<task_t>::get_singleton()->start();
    std::unique_ptr<server_tcp> st_p = std::make_unique<server_tcp>(port, thread_pool_version);


    st_p->start();

    thread_pool<task_t>::get_singleton()->stop();
    thread_pool<task_t>::get_singleton()->join_all();
    

    return 0;
}